package ws.jdbc.concurrent.driver.sqlserver.tds

import ws.utils.io.LittleEndianDataInputStream
import ws.jdbc.concurrent.driver.sqlserver.tds.datastreamtypes.*
import static ws.jdbc.concurrent.driver.sqlserver.tds.datatypes.VARLENTYPE.*
import static ws.jdbc.concurrent.driver.sqlserver.tds.DataTypeDependentDataStreamReader.*
import ws.jdbc.concurrent.driver.sqlserver.tds.datatypes.TypeInfoVarLenType
import ws.utils.ArrayUtil

/**
 * Test the token read methods.
 *
 * @author Wilson Santos, 36228 <wilson.santos@ua.pt>
 */
class TokenReaderTest extends CommonOfflineTest {

  /**
   * Test read ENVCHANGE token.
   */
  void testReadEnvChangeToken() {
    println "testReadEnvChangeToken()\n"
    
    def data = [
      0x1B, 0x00, 0x01, 0x06, 0x6D, 0x00, 0x61, 
      0x00, 0x73, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 
      0x00, 0x06, 0x6D, 0x00, 0x61, 0x00, 0x73, 0x00,
      0x74, 0x00, 0x65, 0x00, 0x72, 0x00,
    ] as Byte[]

    sendData(data)
    def is = receiveData(data.size())
    
    def reader = new EnvChangeTokenReader(is)

    assertEquals 29, reader.read()  // 27 + 2 == 0x1B + 2
    println reader

    assertEquals "master", reader.newValue.getData()
    assertEquals "master", reader.oldValue.getData()
  }

  /**
   * Test read INFO token.
   */
  void testReadInfoToken() {
    println "testReadInfoToken()\n"

    def data = [
      0x58,  0x00,
      0x45,  0x16,  0x00,  0x00,
      0x02,
      0x00,
      0x25,  0x00,
      0x43,  0x00,  0x68,  0x00,  0x61,  0x00,  0x6E,  0x00,  0x67,  0x00,  0x65,  
      0x00,  0x64,  0x00,  0x20,  0x00,  0x64,  0x00,  0x61,  0x00,  0x74,  0x00,
      0x61,  0x00,  0x62,  0x00,  0x61,  0x00,  0x73,  0x00,  0x65,  0x00,  0x20,
      0x00,  0x63,  0x00,  0x6F,  0x00,  0x6E,  0x00,  0x74,  0x00,  0x65,  0x00,
      0x78,  0x00,  0x74,  0x00,  0x20,  0x00,  0x74,  0x00,  0x6F,  0x00,  0x20,
      0x00,  0x27,  0x00,  0x6D,  0x00,  0x61,  0x00,  0x73,  0x00,  0x74,  0x00,
      0x65,  0x00,  0x72,  0x00,  0x27,  0x00,  0x2E,  0x00,
      0x00,
      0x00,  0x00,  0x00,  0x00,  0x00,
    ] as Byte[]

    sendData(data)
    def is = receiveData(data.size())

    def reader = new InfoTokenReader(is)

    assertEquals 90, reader.read()  // 88 + 2 == 0x58 + 2
    println reader
    
    assertEquals "Changed database context to 'master'.", reader.msgText
  }

  /**
   * Test read DONE token.
   */
  void testReadDoneToken() {
    println "testDoneToken()\n"

    def data = [
      //  <Status>
      0x00,  0x00,
      //  </Status>
      //  <CurCmd>
      0x00,  0x00,
      //  </CurCmd>
      //  <DoneRowCount>
      0x00,  0x00, 0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
      //  </DoneRowCount>
    ] as Byte[]

    sendData(data)
    def is = receiveData(data.size())

    def reader = new DoneTokenReader(is)

    assertEquals 12, reader.read()
    println reader

    assertTrue reader.isDoneFinal()
    assertFalse reader.isDoneMore()
    assertFalse reader.isDoneError()
    assertFalse reader.isDoneInxact()
    assertFalse reader.isDoneCount()
    assertFalse reader.isDoneAttn()
    assertFalse reader.isDoneSrvError()
  }

  /**
   * Test read DONEINPROC token.
   */
  void testReadDoneDoneInProcToken() {
    println "testDoneInProcToken()\n"

    def data = [
      //  <Status>
      0x11, 0x00,
      //  </Status>
      //  <CurCmd>
      0xC1, 0x00,
      //  </CurCmd>
      //  <DoneRowCount>
      0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      //  </DoneRowCount>
    ] as Byte[]

    sendData(data)
    def is = receiveData(data.size())

    def reader = new DoneInProcTokenReader(is)

    assertEquals 12, reader.read()
    println reader

    assertTrue reader.isDoneMore()
    assertFalse reader.isDoneError()
    assertFalse reader.isDoneInxact()
    assertTrue reader.isDoneCount()
    assertFalse reader.isDoneSrvError()
  }

  /**
   * Test read DONEPROC token.
   */
  void testReadDoneDoneProcToken() {
    println "testDoneProcToken()\n"

    def data = [
      //  <Status>
      0x00, 0x00,
      //  </Status>
      //  <CurCmd>
      0xE0, 0x00,
      //  </CurCmd>
      //  <DoneRowCount>
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      //  </DoneRowCount>
    ] as Byte[]

    sendData(data)
    def is = receiveData(data.size())

    def reader = new DoneProcTokenReader(is)

    assertEquals 12, reader.read()
    println reader

    assertTrue reader.isDoneFinal()
    assertFalse reader.isDoneMore()
    assertFalse reader.isDoneError()
    assertFalse reader.isDoneInxact()
    assertFalse reader.isDoneCount()
    assertFalse reader.isDoneRPCInBatch()
    assertFalse reader.isDoneSrvError()
  }

  /**
   * Test read LOGINACK token.
   */
  void testLoginAckToken() {
    println "testLoginAckToken()\n"

    def data = [
      //  <Length>
      0x36,  0x00,
      //  </Length>
      //  <Interface>
      0x01,
      //  </Interface>
      //  <TDSVersion>
      0x72,  0x09,  0x00,  0x02,
      //  </TDSVersion>
      //  <ProgName>
      0x16,  0x4D,  0x00,  0x69,  0x00,  0x63,  0x00,  0x72,  0x00,  0x6F,  0x00,
      0x73,  0x00,  0x6F,  0x00,  0x66,  0x00,  0x74,  0x00,  0x20,  0x00,  0x53,
      0x00,  0x51,  0x00,  0x4C,  0x00,  0x20,  0x00,  0x53,  0x00,  0x65,  0x00,
      0x72,  0x00,  0x76,  0x00,  0x65,  0x00,  0x72,  0x00,  0x00,  0x00,  0x00,
      0x00,
      //  </ProgName>
      //  <ProgVersion>
      0x00,  0x00,  0x00,  0x00,
      //  </ProgVersion>
    ] as Byte[]

    sendData(data)
    def is = receiveData(data.size())

    def reader = new LoginAckTokenReader(is)

    assertEquals 56, reader.read()  // 54 + 2  == 0x36 + 2
    println reader
  }

  /**
   * Test read COLINFO token.
   */
  void testColInfoToken() {
    println "testColInfoToken()\n"

    def data = [
      0x06, 0x00, 0x01, 0x00, 0x04, 0x02, 0x00, 0x14,
    ] as Byte[]

    sendData(data)
    def is = receiveData(data.size())
    
    def reader = new ColInfoTokenReader(is)

    assertEquals data.length, reader.read()

    println reader
  }

  /**
   * Test read COLMETADATA token.
   */
  void testColMetaDataToken() {
    println "testColMetaDataToken()\n"

    def data = [
      // <TokenType>
      //0x81,
      // </TokenType>

      // <Count>
      0x01, 0x00,
      // </Count>

      // <ColumnData>
      //  <UserType>
      0x00, 0x00, 0x00, 0x00, 
      //  </UserType>
      
      //  <Flags>
      0x20, 0x00,
      //  </Flags>

      //  <TYPE_INFO>
      0xA7, 0x03, 0x00, 0x09, 0x04, 0xD0, 0x00, 0x34,
      //  </TYPE_INFO>
      
      //  <ColName>
      0x03, 0x62, 0x00, 0x61, 0x00, 0x72, 0x00,
      //  </ColName>
      // <ColumnData>
    ] as Byte[]

    sendData(data)
    def is = receiveData(data.size())
    def reader = new ColMetadataTokenReader(is)

    assertEquals data.length, reader.read()

    println reader
    assertEquals 1, reader.columnList.size()   
  }

  /**
   * Test read COLMETADATA token.
   */
  void testColMetaDataToken2() {
    println "testColMetaDataToken2()\n"

    def data = [
      0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x26, 0x04, 0x04, 0x43,
      0x00, 0x6f, 0x00, 0x6c, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
      0x00, 0xe7, 0x14, 0x00, 0x09, 0x04, 0xd0, 0x00, 0x34, 0x04, 0x43, 0x00,
      0x6f, 0x00, 0x6c, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x38, 0x07, 0x52, 0x00, 0x4f, 0x00, 0x57, 0x00, 0x53, 0x00, 0x54, 0x00,
      0x41, 0x00, 0x54, 0x00
    ] as Byte[]

    sendData(data)
    def is = receiveData(data.size())
    def reader = new ColMetadataTokenReader(is)

    assertEquals data.length, reader.read()
  }

  /**
   * Test read ROW token.
   */
  void testRowToken() {
    println "testRowToken()\n"

    def data = [
      // <TYPE_VARBYTE>
      //  <TYPE_VARLEN>
      0x03, 0x00,
      //  </TYPE_VARLEN>

      //  <BYTES>
      0x66, 0x6F, 0x6F
      //  </BYTES>
      // </TYPE_VARBYTE>
    ] as Byte[]

    sendData(data)
    def is = receiveData(data.size())
    def columnList = new LinkedList<ColumnData>()
    columnList.add(new ColumnData(0, (byte) 0, new TypeInfoVarLenType(BIGVARCHRTYPE, 3), new B_VARCHAR("bar")))
    def reader = new RowTokenReader(is, columnList)

    assertEquals data.length, reader.read()

    println reader
  }

  /**
   * Test read RETURNSTATUS token.
   */
  void testReturnStatusToken() {
    println "testReturnStatusToken()\n"

    def data = [
      // <VALUE>
      //  <LONG>
      0x00, 0x00, 0x00, 0x00,
      //  </LONG>
      // </VALUE>
    ] as Byte[]

    sendData(data)
    def is = receiveData(data.size())
    def reader = new ReturnStatusTokenReader(is)

    assertEquals data.length, reader.read()

    println reader

    assertEquals 0, reader.value
  }

  /**
   * Test read RETURNVALUE token.
   */
  void testReturnValueToken() {
    println "testReturnValueToken()\n"

    def data = [
      0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x26, 0x04, 0x04, 0xfb, 0xde, 0xbc, 0x0a
    ] as Byte[]

    sendData(data)
    def is = receiveData(data.size())
    def reader = new ReturnValueTokenReader(is)

    assertEquals data.length, reader.read()

    println reader
    
  }

  /* ------------------ TEST READ TOKENS FROM FULL MESSAGES -------------------*/

  /** Test read tokens from an login response message. */
  void testReadLoginTokens() {
    println "testReadLoginTokens()\n"

    def data = [
      // <ENVCHANGE>
      //  <TokenType>
      0xE3,  
      //  </TokenType>
      //  <Length>
      0x1B,  0x00,
      //  </Length>
      //  <EnvChangeData>
      0x01,  0x06,  0x6D,  0x00,  0x61,  0x00,  0x73,  0x00,  0x74,  0x00,  0x65,
      0x00,  0x72,  0x00,  0x06,  0x6D,  0x00,  0x61,  0x00,  0x73,  0x00,  0x74,
      0x00,  0x65,  0x00,  0x72,  0x00,
      //  </EnvChangeData>
      // </ENVCHANGE>

      // <INFO>
      //  <TokenType>
      0xAB,
      //  </TokenType>
      //  <Length>
      0x58,  0x00,
      //  </Length>
      0x45,  0x16,  0x00,  0x00,
      0x02,
      0x00,
      0x25,  0x00,
      0x43,  0x00,  0x68,  0x00,  0x61,  0x00,  0x6E,  0x00,  0x67,  0x00,  0x65,  
      0x00,  0x64,  0x00,  0x20,  0x00,  0x64,  0x00,  0x61,  0x00,  0x74,  0x00,
      0x61,  0x00,  0x62,  0x00,  0x61,  0x00,  0x73,  0x00,  0x65,  0x00,  0x20,
      0x00,  0x63,  0x00,  0x6F,  0x00,  0x6E,  0x00,  0x74,  0x00,  0x65,  0x00,
      0x78,  0x00,  0x74,  0x00,  0x20,  0x00,  0x74,  0x00,  0x6F,  0x00,  0x20,
      0x00,  0x27,  0x00,  0x6D,  0x00,  0x61,  0x00,  0x73,  0x00,  0x74,  0x00,
      0x65,  0x00,  0x72,  0x00,  0x27,  0x00,  0x2E,  0x00,
      0x00,
      0x00,  0x00,  0x00,  0x00,  0x00,
      // </INFO>

      // <ENVCHANGE>
      0xE3,
      0x08,  0x00,
      0x07,  0x05,  0x09,  0x04,  0xD0,  0x00,  0x34,  0x00,

      // <ENVCHANGE>
      0xE3,
      0x17,  0x00,
      0x02,  0x0A,  0x75,  0x00,  0x73,  0x00,  0x5F,  0x00,  0x65,  0x00,  0x6E,
      0x00,  0x67,  0x00,  0x6C,  0x00,  0x69,
      0x00,  0x73,  0x00,  0x68,  0x00,  0x00,

      // <ENVCHANGE...>
      0xE3,
      0x13,  0x00,
      0x04,  0x04,  0x34,  0x00,  0x30,  0x00,  0x39,  0x00,  0x36,  0x00,  0x04,
      0x34,  0x00,  0x30,  0x00,  0x39,  0x00,  0x36,  0x00,  0xAB,  0x5C,  0x00,
      0x47,  0x16,  0x00,  0x00,  0x01,  0x00,  0x27,  0x00,  0x43,  0x00,  0x68,
      0x00,  0x61,  0x00,  0x6E,  0x00,  0x67,  0x00,  0x65,  0x00,  0x64,  0x00,
      0x20,  0x00,  0x6C,  0x00,  0x61,  0x00,  0x6E,  0x00,  0x67,  0x00,  0x75,
      0x00,  0x61,  0x00,  0x67,  0x00,  0x65,  0x00,  0x20,  0x00,  0x73,  0x00,  
      0x65,  0x00,  0x74,  0x00,  0x74,  0x00,  0x69,  0x00,  0x6E,  0x00,  0x67,
      0x00,  0x20,  0x00,  0x74,  0x00,  0x6F,  0x00,  0x20,  0x00,  0x75,  0x00,
      0x73,  0x00,  0x5F,  0x00,  0x65,  0x00,  0x6E,  0x00,  0x67,  0x00,  0x6C,
      0x00,  0x69,  0x00,  0x73,  0x00,  0x68,  0x00,  0x2E,  0x00,  0x00,  0x00,
      0x00,  0x00,  0x00,  0x00,

      // <LOGINACK>
      //  <TokenType>
      0xAD,
      //  </TokenType>
      //  <Length>
      0x36,  0x00,
      //  </Length>
      //  <Interface>
      0x01,
      //  </Interface>
      //  <TDSVersion>
      0x72,  0x09,  0x00,  0x02,
      //  </TDSVersion>
      //  <ProgName>
      0x16,  0x4D,  0x00,  0x69,  0x00,  0x63,  0x00,  0x72,  0x00,  0x6F,  0x00,
      0x73,  0x00,  0x6F,  0x00,  0x66,  0x00,  0x74,  0x00,  0x20,  0x00,  0x53,
      0x00,  0x51,  0x00,  0x4C,  0x00,  0x20,  0x00,  0x53,  0x00,  0x65,  0x00,
      0x72,  0x00,  0x76,  0x00,  0x65,  0x00,  0x72,  0x00,  0x00,  0x00,  0x00,
      0x00,
      //  </ProgName>
      //  <ProgVersion>
      0x00,  0x00,  0x00,  0x00,
      //  </ProgVersion>
      // </LOGINACK>

      // <DONE>
      //  <TokenType>
      0xFD,
      //  </TokenType>
      //  <Status>
      0x00,  0x00,
      //  </Status>
      //  <CurCmd>
      0x00,  0x00,
      //  </CurCmd>
      0x00,  0x00,
      //  <DoneRowCount>
      0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
      //  </DoneRowCount>
      // </DONE>
    ] as Byte[]

    sendData(data)
    def is = receiveDataWithSize(data.size())
    
    def collection = TokenReader.readTokens(is)
    println collection
  }

  /** Test read tokens from an SQL Batch Server Response message. */
  void testReadSQLBatchTokens() {
    println "testReadSQLBatchTokens()\n"

    def data = [
      // <COLMETADATA>
      0x81, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0xA7, 0x03, 0x00, 
      0x09, 0x04, 0xD0, 0x00, 0x34, 0x03, 0x62, 0x00, 0x61, 0x00, 0x72, 0x00,
      // </COLMETADATA>
      
      // <ROW>
      0xD1, 0x03, 0x00, 0x66, 0x6F, 0x6F, 0xFD, 0x10, 0x00, 0xC1, 0x00, 0x01, 
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      // </ROW>
    ] as Byte[]

    sendData(data)
    def is = receiveDataWithSize(data.size())

    def collection = TokenReader.readTokens(is)
    println collection

    assertEquals 3, collection.size()
  }

  /** Test read tokens from an SQL RPC Server Response message. */
  void testRPCServerResponseTokens() {
    println "testRPCServerResponseTokens()\n"

    def data = [
      0xFF, 0x11, 0x00, 0xC1, 0x00, 0x01, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xE0, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    ] as Byte[]

    sendData(data)
    def is = receiveDataWithSize(data.size())

    def collection = TokenReader.readTokens(is)
    println collection

    assertEquals 3, collection.size()
  }
}